In the previous CarDelegate example, we explicitly created instances of the Car.CarEngineHandler delegate object in order to register and unregister with the engine notifications:
static void Main(string[] args) { Console.WriteLine("***** Delegates as event enablers *****\n"); Car c1 = new Car("SlugBug", 100, 10); c1.RegisterWithCarEngine(new Car.CarEngineHandler(OnCarEngineEvent)); Car.CarEngineHandler handler2 = new Car.CarEngineHandler(OnCarEngineEvent2); c1.RegisterWithCarEngine(handler2); ... }
To be sure, if you need to call any of the inherited members of MulticastDelegate or Delegate, manually creating a delegate variable is the most straightforward way of doing so. However, in most cases, you don’t really need to hang onto the delegate object. Rather, you typically only need to use the delegate object in order to pass in the method name as a constructor parameter.
As a simplification, C# provides a shortcut termed method group conversion. This feature allows you to supply a direct method name, rather than a delegate object, when calling methods that take delegates as arguments.
Note As you will see later in this chapter, you can also use method group conversion syntax to simplify how you register with a C# event.
To illustrate, create a new Console Application named CarDelegateMethodGroupConversion and insert the file containing the Car class you defined in the CarDelegate project. Now, consider the following Program class, which uses method group conversion to register and unregister from the engine notifications:
class Program { static void Main(string[] args) { Console.WriteLine("***** Method Group Conversion *****\n"); Car c1 = new Car(); // Register the simple method name. c1.RegisterWithCarEngine(CallMeHere); Console.WriteLine("***** Speeding up *****"); for (int i = 0; i < 6; i++) c1.Accelerate(20); // Unregister the simple method name. c1.UnRegisterWithCarEngine(CallMeHere); // No more notifications! for (int i = 0; i < 6; i++) c1.Accelerate(20); Console.ReadLine(); } static void CallMeHere(string msg) { Console.WriteLine("=> Message from Car: {0}", msg); } }
Notice that we are not directly allocating the associated delegate object, but rather simply specifying a method that matches the delegate’s expected signature (a method returning void and taking a single string in this case). Understand that the C# compiler is still ensuring type safety. Thus, if the CallMeHere() method did not take a string and return void, we would be issued a compiler error.
Source Code The CarDelegateMethodGroupConversion project is located under the Chapter 11 subdirectory.